/*
 * Created on 21-Jun-2004
 * Created by Paul Gardner
 * Copyright (C) Azureus Software, Inc, All Rights Reserved.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 */

package org.gudy.azureus2.core3.internat;

import java.io.File;
import java.io.UnsupportedEncodingException;

import org.gudy.azureus2.core3.util.ByteFormatter;
import org.gudy.azureus2.core3.util.SHA1Hasher;

/**
 * @author parg
 * 
 */

public class LocaleUtilDecoderFallback implements LocaleUtilDecoder {
    public static String NAME = "Fallback";

    private static volatile int max_ok_name_length = 64;
    private static volatile boolean max_ok_name_length_determined;

    // don't change these, it'll stuff up people with torrents that are using the
    // fallback encoding

    private static final String VALID_CHARS = "abcdefghijklmnopqrstuvwxyz1234567890_-.";

    private int index;

    protected LocaleUtilDecoderFallback(int _index) {
        index = _index;
    }

    public String getName() {
        return (NAME);
    }

    public int getIndex() {
        return (index);
    }

    public String tryDecode(byte[] bytes, boolean lax) {
        return (decode(bytes));
    }

    public String decodeString(byte[] bytes)

    throws UnsupportedEncodingException {
        return (decode(bytes));
    }

    protected String decode(byte[] data) {
        if (data == null) {

            return (null);
        }

        StringBuffer res = new StringBuffer(data.length * 2);

        for (int i = 0; i < data.length; i++) {

            byte c = data[i];

            if (VALID_CHARS.indexOf(Character.toLowerCase((char) c)) != -1) {

                res.append((char) c);

            } else {

                res.append("_");
                res.append(ByteFormatter.nicePrint(c));
            }
        }

        // more often that not these decoded values are used for filenames. Windows has a limit
        // of 250 (ish) chars, so we do something sensible with longer values

        int len = res.length();

        if (len > max_ok_name_length) {

            // could be a file system out there that supports arbitarily long names, so
            // we can't pre-calculate the max

            if ((!max_ok_name_length_determined) && fileLengthOK(len)) {

                // this length is ok, bump up the known limit

                max_ok_name_length = len;

            } else {

                // won't fit

                if (!max_ok_name_length_determined) {

                    for (int i = max_ok_name_length + 16; i < len; i += 16) {

                        if (fileLengthOK(i)) {

                            max_ok_name_length = i;

                        } else {

                            break;
                        }
                    }

                    max_ok_name_length_determined = true;
                }

                // try and preserve extension

                String extension = null;

                int pos = res.lastIndexOf(".");

                if (pos != -1) {

                    // include the "."

                    extension = res.substring(pos);

                    if (extension.length() == 1 || extension.length() > 4) {

                        extension = null;
                    }
                }
                // replace the end of the string with a hash value to ensure uniqueness

                byte[] hash = new SHA1Hasher().calculateHash(data);

                String hash_str = ByteFormatter.nicePrint(hash, true);

                res = new StringBuffer(res.substring(0, max_ok_name_length - hash_str.length() - (extension == null ? 0 : extension.length())));

                res.append(hash_str);

                if (extension != null) {

                    res.append(extension);
                }
            }
        }

        return (res.toString());
    }

    protected boolean fileLengthOK(int len) {
        StringBuffer n = new StringBuffer(len);

        for (int i = 0; i < len; i++) {

            n.append("A");
        }

        try {
            File f = File.createTempFile(n.toString(), "");

            f.delete();

            return (true);

        } catch (Throwable e) {

            return (false);
        }
    }
}
